package com.xiangyang.aspect;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.xiangyang.annotations.OperationLog;
import com.xiangyang.entity.BaseEntity;
import com.xiangyang.entity.LoginUser;
import com.xiangyang.entity.OperLog;
import com.xiangyang.service.impl.OperLogService;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class OperationLogAspect {

    @Autowired
    private OperLogService operLogService;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Around("@annotation(com.xiangyang.annotations.OperationLog)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object oldData = null;
        Object newData = null;

        try {
            // 获取旧数据
            if (isUpdateOrDeleteOperation(joinPoint)) {
                oldData = getOldData(joinPoint);
            }

            // 执行方法
            Object result = joinPoint.proceed();

            // 获取新数据（仅适用于更新操作）
            if (isUpdateOperation(joinPoint)) {
                newData = getNewData(joinPoint);
            }

            // 记录日志
            saveOperLog(joinPoint, result, null, oldData, newData, startTime);
            return result;
        } catch (Exception e) {
            // 记录异常日志
            saveOperLog(joinPoint, null, e, oldData, newData, startTime);
            throw e;
        }
    }

    private boolean isUpdateOrDeleteOperation(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        return method.getName().startsWith("update") || method.getName().startsWith("delete");
    }

    private boolean isUpdateOperation(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        return method.getName().startsWith("update");
    }

    private Object getOldData(JoinPoint joinPoint) {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            OperationLog annotation = method.getAnnotation(OperationLog.class);
            String oldDataMethod = annotation.oldDataMethod();

            if (!oldDataMethod.isEmpty()) {
                Object target = joinPoint.getTarget();
                Class<?> targetClass = target.getClass();
                Method oldDataMethodObj = targetClass.getMethod(oldDataMethod, Long.class);
                Object[] args = joinPoint.getArgs();
                Long id = null;

                if (args.length > 0) {
                    for (Object arg : args) {
                        if (arg instanceof Long) {
                            id = (Long) arg;
                            break;
                        } else if (arg instanceof BaseEntity) {
                            BaseEntity baseEntity = (BaseEntity) arg;
                            id = baseEntity.getId();
                            break;
                        }
                    }
                }

                if (id != null) {
                    return oldDataMethodObj.invoke(target, id);
                } else {
                    System.err.println("无法获取 ID");
                }
            }
        } catch (Exception e) {
            // 处理异常
            e.printStackTrace();
            if (e.getCause() != null) {
                System.err.println("内部异常: " + e.getCause().getMessage());
            }
        }
        return null;
    }

    private Object getNewData(JoinPoint joinPoint) {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            OperationLog annotation = method.getAnnotation(OperationLog.class);
            String newDataMethod = annotation.newDataMethod();

            if (!newDataMethod.isEmpty()) {
                Object target = joinPoint.getTarget();
                Class<?> targetClass = target.getClass();
                Method newDataMethodObj = targetClass.getMethod(newDataMethod, Long.class);
                Object[] args = joinPoint.getArgs();
                Long id = null;

                if (args.length > 0) {
                    for (Object arg : args) {
                        if (arg instanceof BaseEntity) {
                            BaseEntity baseEntity = (BaseEntity) arg;
                            id = baseEntity.getId();
                            break;
                        }
                    }
                }

                if (id != null) {
                    return newDataMethodObj.invoke(target, id);
                } else {
                    System.err.println("无法获取 ID");
                }
            }
        } catch (Exception e) {
            // 处理异常
            e.printStackTrace();
            if (e.getCause() != null) {
                System.err.println("内部异常: " + e.getCause().getMessage());
            }
        }
        return null;
    }

    private void saveOperLog(JoinPoint joinPoint, Object result, Exception e, Object oldData, Object newData, long startTime) {
        // 获取请求的参数
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String operUrl = request.getRequestURI();
        String operIp = request.getRemoteAddr();

        // 从 SecurityContext 中获取当前认证的用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String operName = "anonymous";
        String userPhone = "null";
        String operatorType = "user";

        if (authentication != null && authentication.getPrincipal() instanceof LoginUser) {
            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
            operName = loginUser.getUserDetailInfo().getUserName();
            userPhone= loginUser.getUserDetailInfo().getUserPhone();
            operatorType = loginUser.getUserDetailInfo().getUserType();
        } else {
            System.out.println("未找到认证用户信息或 Principal 不是 LoginUser 类型");
        }
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取方法上的注解
        OperationLog operationLogAnnotation = method.getAnnotation(OperationLog.class);

        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        Map<String, String> params = new HashMap<>();
        String[] parameterNames = signature.getParameterNames();
        for (int i = 0; i < args.length; i++) {
            params.put(parameterNames[i], args[i].toString());
        }

        // 创建日志对象
        OperLog log = new OperLog();
        log.setTitle(operationLogAnnotation.title());
        log.setBusinessType(operationLogAnnotation.businessType());
        log.setMethod(method.getName());
        log.setRequestMethod(request.getMethod());
        log.setOperatorType(operatorType); // 默认操作类型为USER
        log.setOperName(operName);
        log.setUserPhone(userPhone); // 添加用户ID
        log.setOperUrl(operUrl);
        log.setOperIp(operIp);
        log.setOperParam(params.toString());
        log.setOperTime(new Date());
        log.setExecuteTime(System.currentTimeMillis() - startTime);

        if (e != null) {
            log.setErrorMsg(e.getMessage());
            log.setStatus(-1); // 异常状态
        } else {
            try {
                log.setJsonResult(objectMapper.writeValueAsString(result));
            } catch (Exception ex) {
                log.setJsonResult(ex.getMessage());
            }
            log.setStatus(1); // 成功状态
        }

        // 记录旧数据和新数据
        if (oldData != null) {
            try {
                log.setOldData(objectMapper.writeValueAsString(oldData));
            } catch (JsonProcessingException ex) {
                throw new RuntimeException(ex);
            }
        }
        if (newData != null) {
            try {
                log.setNewData(objectMapper.writeValueAsString(newData));
            } catch (JsonProcessingException ex) {
                throw new RuntimeException(ex);
            }
        }

        // 保存日志
        operLogService.save(log);
    }
}